home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 2848 / 2848.xpi / chrome / passwordexporter.jar / content / storage-Legacy.js < prev   
Text File  |  2009-08-04  |  12KB  |  285 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is mozilla.org code.
  15.  *
  16.  * The Initial Developer of the Original Code is Mozilla Corporation.
  17.  * Portions created by the Initial Developer are Copyright (C) 2007
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *  Justin Dolske <dolske@mozilla.com> (original author)
  22.  *
  23.  * Alternatively, the contents of this file may be used under the terms of
  24.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  25.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26.  * in which case the provisions of the GPL or the LGPL are applicable instead
  27.  * of those above. If you wish to allow use of your version of this file only
  28.  * under the terms of either the GPL or the LGPL, and not to allow others to
  29.  * use your version of this file under the terms of the MPL, indicate your
  30.  * decision by deleting the provisions above and replace them with the notice
  31.  * and other provisions required by the GPL or the LGPL. If you do not delete
  32.  * the provisions above, a recipient may use your version of this file under
  33.  * the terms of any one of the MPL, the GPL or the LGPL.
  34.  *
  35.  * ***** END LICENSE BLOCK ***** */
  36.  
  37. // http://mxr.mozilla.org/mozilla/source/toolkit/components/passwordmgr/src/storage-Legacy.js
  38.  
  39. /**
  40.  * Changes:
  41.  *  log() -> passwordExporter.debug()
  42.  *  this.log -> passwordExporter.debug()
  43.  * extraLogin encryption
  44.  */
  45.  
  46. var passwordExporterStorageLegacy = {
  47.     
  48.      __ioService: null, // IO service for string -> nsIURI conversion
  49.     get _ioService() {
  50.         if (!this.__ioService)
  51.             this.__ioService = Components.classes["@mozilla.org/network/io-service;1"].
  52.                                getService(Components.interfaces.nsIIOService);
  53.         return this.__ioService;
  54.     },
  55.     
  56.     __decoderRing : null,  // nsSecretDecoderRing service
  57.     get _decoderRing() {
  58.         if (!this.__decoderRing)
  59.             this.__decoderRing = Components.classes["@mozilla.org/security/sdr;1"].
  60.                                  getService(Components.interfaces.nsISecretDecoderRing);
  61.         return this.__decoderRing;
  62.     },
  63.     
  64.     /*
  65.      * _upgrade_entry_to_2E
  66.      *
  67.      * Updates the format of an entry from 2D to 2E. Returns an array of
  68.      * logins (1 or 2), as sometimes updating an entry requires creating an
  69.      * extra login.
  70.      */
  71.     _upgrade_entry_to_2E : function (aLogin) {
  72.         var upgradedLogins = [aLogin];
  73.  
  74.         /*
  75.          * For logins stored from HTTP channels
  76.          *    - scheme needs to be derived and prepended
  77.          *    - blank or missing realm becomes same as hostname.
  78.          *
  79.          *  "site.com:80"  --> "http://site.com"
  80.          *  "site.com:443" --> "https://site.com"
  81.          *  "site.com:123" --> Who knows! (So add both)
  82.          *
  83.          * Note: For HTTP logins, the hostname never contained a username
  84.          *       or password. EG "user@site.com:80" shouldn't ever happen.
  85.          *
  86.          * Note: Proxy logins are also stored in this format.
  87.          */
  88.         if (aLogin.hostname.indexOf("://") == -1) {
  89.             var oldHost = aLogin.hostname;
  90.  
  91.             // Parse out "host:port".
  92.             try {
  93.                 // Small hack: Need a scheme for nsIURI, so just prepend http.
  94.                 // We'll check for a port == -1 in case nsIURI ever starts
  95.                 // noticing that "http://foo:80" is using the default port.
  96.                 var uri = this._ioService.newURI("http://" + aLogin.hostname,
  97.                                                  null, null);
  98.                 var host = uri.host;
  99.                 var port = uri.port;
  100.             } catch (e) {
  101.                 passwordExporter.debug("2E upgrade: Can't parse hostname " + aLogin.hostname);
  102.                 return upgradedLogins;
  103.             }
  104.  
  105.             if (port == 80 || port == -1)
  106.                 aLogin.hostname = "http://" + host;
  107.             else if (port == 443)
  108.                 aLogin.hostname = "https://" + host;
  109.             else {
  110.                 // Not a standard port! Could be either http or https!
  111.                 // (Or maybe it's a proxy login!) To try and avoid
  112.                 // breaking logins, we'll add *both* http and https
  113.                 // versions.
  114.                 passwordExporter.debug("2E upgrade: Cloning login for " + aLogin.hostname);
  115.  
  116.                 aLogin.hostname = "http://" + host + ":" + port;
  117.  
  118.                 var extraLogin = Components.classes["@mozilla.org/login-manager/loginInfo;1"].
  119.                                  createInstance(Components.interfaces.nsILoginInfo);
  120.                 /*extraLogin.init("https://" + host + ":" + port,
  121.                                 null, aLogin.httpRealm,
  122.                                 null, null, "", "");
  123.                 // We don't have decrypted values, so clone the encrypted
  124.                 // bits into the new entry.
  125.                 extraLogin.wrappedJSObject.encryptedPassword = 
  126.                     aLogin.wrappedJSObject.encryptedPassword;
  127.                 extraLogin.wrappedJSObject.encryptedUsername = 
  128.                     aLogin.wrappedJSObject.encryptedUsername;*/
  129.                 extraLogin.init("https://" + host + ":" + port,
  130.                                 null, aLogin.httpRealm,
  131.                                 aLogin.username, aLogin.password, "", "");
  132.  
  133.                 if (extraLogin.httpRealm == "")
  134.                     extraLogin.httpRealm = extraLogin.hostname;
  135.                 
  136.                 upgradedLogins.push(extraLogin);
  137.             }
  138.  
  139.             // If the server didn't send a realm (or it was blank), we
  140.             // previously didn't store anything.
  141.             if (aLogin.httpRealm == "")
  142.                 aLogin.httpRealm = aLogin.hostname;
  143.  
  144.             passwordExporter.debug("2E upgrade: " + oldHost + " ---> " + aLogin.hostname);
  145.  
  146.             return upgradedLogins;
  147.         }
  148.  
  149.  
  150.         /*
  151.          * For form logins and non-HTTP channel logins (both were stored in
  152.          * the same format):
  153.          *
  154.          * Standardize URLs (.hostname and .actionURL)
  155.          *    - remove default port numbers, if specified
  156.          *      "http://site.com:80"  --> "http://site.com"
  157.          *    - remove usernames from URL (may move into aLogin.username)
  158.          *      "ftp://user@site.com" --> "ftp://site.com"
  159.          *
  160.          * Note: Passwords in the URL ("foo://user:pass@site.com") were not
  161.          *       stored in FF2, so no need to try to move the value into
  162.          *       aLogin.password.
  163.          */
  164.  
  165.         // closures in cleanupURL
  166.         var ioService = this._ioService;
  167.         var log = this.log;
  168.  
  169.         function cleanupURL(aURL) {
  170.             var newURL, username = null;
  171.  
  172.             try {
  173.                 var uri = ioService.newURI(aURL, null, null);
  174.  
  175.                 var scheme = uri.scheme;
  176.                 newURL = scheme + "://" + uri.host;
  177.  
  178.                 // If the URL explicitly specified a port, only include it when
  179.                 // it's not the default. (We never want "http://foo.com:80")
  180.                 port = uri.port;
  181.                 if (port != -1) {
  182.                     var handler = ioService.getProtocolHandler(scheme);
  183.                     if (port != handler.defaultPort)
  184.                         newURL += ":" + port;
  185.                 }
  186.  
  187.                 // Could be a channel login with a username. 
  188.                 if (scheme != "http" && scheme != "https" && uri.username)
  189.                     username = uri.username;
  190.                 
  191.             } catch (e) {
  192.                 passwordExporter.debug("Can't cleanup URL: " + aURL);
  193.                 newURL = aURL;
  194.             }
  195.  
  196.             if (newURL != aURL)
  197.                 passwordExporter.debug("2E upgrade: " + aURL + " ---> " + newURL);
  198.  
  199.             return [newURL, username];
  200.         }
  201.  
  202.         var isFormLogin = (aLogin.formSubmitURL ||
  203.                            aLogin.usernameField ||
  204.                            aLogin.passwordField);
  205.  
  206.         var [hostname, username] = cleanupURL(aLogin.hostname);
  207.         aLogin.hostname = hostname;
  208.  
  209.         // If a non-HTTP URL contained a username, it wasn't stored in the
  210.         // encrypted username field (which contains an encrypted empty value)
  211.         // (Don't do this if it's a form login, though.)
  212.         if (username && !isFormLogin) {
  213.             var [encUsername, userCanceled] = this._encrypt(username);
  214.             if (!userCanceled)
  215.                 aLogin.wrappedJSObject.encryptedUsername = encUsername;
  216.         }
  217.  
  218.  
  219.         if (aLogin.formSubmitURL) {
  220.             [hostname, username] = cleanupURL(aLogin.formSubmitURL);
  221.             aLogin.formSubmitURL = hostname;
  222.             // username, if any, ignored.
  223.         }
  224.  
  225.  
  226.         /*
  227.          * For logins stored from non-HTTP channels
  228.          *    - Set httpRealm so they don't look like form logins
  229.          *     "ftp://site.com" --> "ftp://site.com (ftp://site.com)"
  230.          *
  231.          * Tricky: Form logins and non-HTTP channel logins are stored in the
  232.          * same format, and we don't want to add a realm to a form login.
  233.          * Form logins have field names, so only update the realm if there are
  234.          * no field names set. [Any login with a http[s]:// hostname is always
  235.          * a form login, so explicitly ignore those just to be safe.]
  236.          *
  237.          * Bug 403790: mail entries (imap://, ldaps://, mailbox:// smtp:// have
  238.          * fieldnames set to "\=username=\" and "\=password=\" (non-escaping
  239.          * backslash). More work is needed to upgrade these properly.
  240.          */
  241.         const isHTTP = /^https?:\/\//;
  242.         if (!isHTTP.test(aLogin.hostname) && !isFormLogin) {
  243.             aLogin.httpRealm = aLogin.hostname;
  244.             aLogin.formSubmitURL = null;
  245.             passwordExporter.debug("2E upgrade: set empty realm to " + aLogin.httpRealm);
  246.         }
  247.  
  248.         return upgradedLogins;
  249.     },
  250.  
  251.     /*
  252.      * _encrypt
  253.      *
  254.      * Encrypts the specified string, using the SecretDecoderRing.
  255.      *
  256.      * Returns [cipherText, userCanceled] where:
  257.      *  cipherText   -- the encrypted string, or null if it failed.
  258.      *  userCanceled -- if the encryption failed, this is true if the
  259.      *                  user selected Cancel when prompted to enter their
  260.      *                  Master Password. The caller should bail out, and not
  261.      *                  not request that more things be encrypted (which 
  262.      *                  results in prompting the user for a Master Password
  263.      *                  over and over.)
  264.      */
  265.     _encrypt : function (plainText) {
  266.         var cipherText = null, userCanceled = false;
  267.  
  268.         try {
  269.             var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
  270.                             createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
  271.             converter.charset = "UTF-8";
  272.             var plainOctet = converter.ConvertFromUnicode(plainText);
  273.             plainOctet += converter.Finish();
  274.             cipherText = this._decoderRing.encryptString(plainOctet);
  275.         } catch (e) {
  276.             this.passwordExporter.debug("Failed to encrypt string. (" + e.name + ")");
  277.             // If the user clicks Cancel, we get NS_ERROR_FAILURE.
  278.             // (unlike decrypting, which gets NS_ERROR_NOT_AVAILABLE).
  279.             if (e.result == Components.results.NS_ERROR_FAILURE)
  280.                 userCanceled = true;
  281.         }
  282.  
  283.         return [cipherText, userCanceled];
  284.     }
  285. };